package br.com.gbvbahia.vendas.controllers;

import br.com.gbvbahia.vendas.modelos.Pedido;
import br.com.gbvbahia.vendas.controllers.util.JsfUtil;
import br.com.gbvbahia.vendas.controllers.util.PaginationHelper;
import br.com.gbvbahia.vendas.beans.PedidoFacade;
import br.com.gbvbahia.vendas.beans.ProdutoFacade;
import br.com.gbvbahia.vendas.modelos.Cliente;
import br.com.gbvbahia.vendas.modelos.ItensPedido;
import br.com.gbvbahia.vendas.modelos.Produto;
import br.com.gbvbahia.vendas.modelos.enums.StatusPedido;
import br.com.gbvbahia.vendas.report.PedidosTO;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ResourceBundle;
import javax.ejb.EJB;
import javax.inject.Named;
import javax.enterprise.context.SessionScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;

@Named("pedidoController")
@SessionScoped
public class PedidoController implements Serializable {

    @EJB
    private ProdutoFacade produtoFacade;
    @EJB
    private br.com.gbvbahia.vendas.beans.PedidoFacade ejbFacade;
    private Cliente clientePedido;
    private Pedido current;
    private DataModel items = null;
    private PaginationHelper pagination;
    private int selectedItemIndex;
    private List<Produto> produtosSelecionados;
    //Filtro
    private String telFiltro;
    private String nomeFiltro;
    private StatusPedido statusFiltro;

    public PedidoController() {
    }

    public Pedido getSelected() {
        if (current == null) {
            current = new Pedido();
            current.setCliente(clientePedido);
            selectedItemIndex = -1;
        }
        return current;
    }

    private PedidoFacade getFacade() {
        return ejbFacade;
    }

    public PaginationHelper getPagination() {
        if (pagination == null) {
            pagination = new PaginationHelper(10) {
                @Override
                public int getItemsCount() {
                    return getFacade().contarPedidos(telFiltro, nomeFiltro, statusFiltro);
                }

                @Override
                public DataModel createPageDataModel() {
                    return new ListDataModel(getFacade().
                            buscarPedidos(telFiltro, nomeFiltro, statusFiltro,
                            new int[]{getPageFirstItem(), getPageFirstItem() + getPageSize()}));
                }
            };
        }
        return pagination;
    }

    public String imprimirEntrega() {
        List<Pedido> pedidos = new ArrayList<Pedido>();
        for (Iterator it = getItems().iterator(); it.hasNext();) {
            Pedido p = (Pedido) it.next();
            if (p.isMarcado()) {
                pedidos.add(p);
            }
        }
        if (pedidos.isEmpty()) {
            JsfUtil.addWarnMessage("Pelo menos um pedido deve ser selecionado");
        } else {
            PedidosTO dto = new PedidosTO(pedidos);
            List dtos = new ArrayList();
            dtos.add(dto);
            JsfUtil.genereteExcelReport("vendasPrincipal.jasper", new JRBeanCollectionDataSource(dtos), FacesContext.getCurrentInstance());
        }
        return null;
    }

    public String prepareList() {
        recreateModel();
        return "List";
    }

    public String prepareView() {
        current = (Pedido) getItems().getRowData();
        selectedItemIndex = getPagination().getPageFirstItem() + getItems().getRowIndex();
        return "View";
    }

    public String prepareCreate() {
        current = new Pedido();
        current.setCliente(clientePedido);
        selectedItemIndex = -1;
        produtosSelecionados = null;
        return "Create";
    }

    public String create() {
        try {
            if (getProdutosSelecionados().isEmpty()) {
                JsfUtil.addWarnMessage("Selecione um produto");
                return null;
            }
            getFacade().realizarPedido(current, produtosSelecionados);
            produtosSelecionados = null;
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/bundle").getString("PedidoCreated"));
            return "View";
        } catch (Exception e) {
             e.printStackTrace();
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    public String prepareEdit() {
        current = (Pedido) getItems().getRowData();
        selectedItemIndex = getPagination().getPageFirstItem() + getItems().getRowIndex();
        produtosSelecionados = null;
        for (ItensPedido itens : current.getItens()) {
            getProdutosSelecionados().add(itens.getProduto());
        }
        return "Edit";
    }

    public String update() {
        try {
            getFacade().edit(current);
            produtosSelecionados = null;
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/bundle").getString("PedidoUpdated"));
            return "View";
        } catch (Exception e) {
             e.printStackTrace();
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    public String destroy() {
        try {
            current = (Pedido) getItems().getRowData();
            selectedItemIndex = getPagination().getPageFirstItem() + getItems().getRowIndex();
            current.setStatus(StatusPedido.CANCELADO);
            getFacade().edit(current);
            produtosSelecionados = null;
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/bundle").getString("PedidoCancelado"));
            recreatePagination();
            recreateModel();
            return "List";
        } catch (Exception e) {
             e.printStackTrace();
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/bundle").getString("PersistenceErrorOccured"));
            return null;
        }
    }

    public String finalizarAndView() {
        finalizarPedido(current);
        recreateModel();
        updateCurrentItem();
        return "List";
    }

    public void finalizarPedido(Pedido pedido) {
        try {
            pedido.setStatus(StatusPedido.FINALIZADO);
            getFacade().edit(pedido);
            produtosSelecionados = null;
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/bundle").getString("PedidoFinalizado"));
        } catch (Exception e) {
            e.printStackTrace();
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/bundle").getString("PersistenceErrorOccured"));
        }
    }

    public String destroyAndView() {
        performDestroy();
        recreateModel();
        updateCurrentItem();
        return "List";
    }

    private void performDestroy() {
        try {
            current.setStatus(StatusPedido.CANCELADO);
            getFacade().edit(current);
            produtosSelecionados = null;
            JsfUtil.addSuccessMessage(ResourceBundle.getBundle("/bundle").getString("PedidoCancelado"));
        } catch (Exception e) {
             e.printStackTrace();
            JsfUtil.addErrorMessage(e, ResourceBundle.getBundle("/bundle").getString("PersistenceErrorOccured"));
        }
    }

    private void updateCurrentItem() {
        int count = getFacade().count();
        if (selectedItemIndex >= count) {
            // selected index cannot be bigger than number of items:
            selectedItemIndex = count - 1;
            // go to previous page if last page disappeared:
            if (getPagination().getPageFirstItem() >= count) {
                pagination.previousPage();
            }
        }
        if (selectedItemIndex >= 0) {
            current = getFacade().findRange(new int[]{selectedItemIndex, selectedItemIndex + 1}).get(0);
        }
    }

    public DataModel getItems() {
        if (items == null) {
            items = getPagination().createPageDataModel();
        }
        return items;
    }

    public void recreateModel() {
        items = null;
    }

    private void recreatePagination() {
        pagination = null;
    }

    public String next() {
        getPagination().nextPage();
        recreateModel();
        return "List";
    }

    public String previous() {
        getPagination().previousPage();
        recreateModel();
        return "List";
    }

    public SelectItem[] getItemsAvailableSelectMany() {
        return JsfUtil.getSelectItems(ejbFacade.findAll(), false);
    }

    public SelectItem[] getItemsAvailableSelectOne() {
        return JsfUtil.getSelectItems(ejbFacade.findAll(), true);
    }

    public SelectItem[] getEnderecosClientePedidoSelect() {
        return JsfUtil.getSelectItems(clientePedido.getEndereco(), true);
    }

    public SelectItem[] getTelefonesClientePedidoSelect() {
        return JsfUtil.getSelectItems(clientePedido.getTelefones(), true);
    }

    public List<SelectItem> getStatusPedidoSelect() {
        List<SelectItem> toReturn = new ArrayList<SelectItem>();
        for (StatusPedido sp : StatusPedido.values()) {
            toReturn.add(new SelectItem(sp, sp.getStatus()));
        }
        return toReturn;
    }

    public Pedido getPedido(java.lang.Integer id) {
        return ejbFacade.find(id);
    }

    public List<Produto> getProdutosSelecionados() {
        if (produtosSelecionados == null) {
            produtosSelecionados = new ArrayList<Produto>();
        }
        return produtosSelecionados;
    }

    public void setProdutosSelecionados(List<Produto> produtosSelecionados) {
        this.produtosSelecionados = produtosSelecionados;
    }

    public void addProduto(Produto p) {
        if (getProdutosSelecionados().contains(p)) {
            Produto produto = getProdutosSelecionados().get(getProdutosSelecionados().indexOf(p));
            produto.setQtdade(produto.getQtdade() + 1);
        } else {
            Produto prod = produtoFacade.find(p.getId());
            prod.setQtdade(1);
            getProdutosSelecionados().add(prod);
        }
    }

    public void novoPedido(Cliente cliente) {
        clientePedido = cliente;
        prepareCreate();
    }

    public Double getValorTotalPedido() {
        Double toReturn = 0.0d;
        for (Produto p : getProdutosSelecionados()) {
            toReturn += p.getPreco() * p.getQtdade();
        }
        toReturn = toReturn - getSelected().getDesconto();
        return toReturn;
    }

    public Double calcularValorTotalPedido(Pedido p) {
        Double toReturn = 0.0d;
        for (ItensPedido ip : p.getItens()) {
            toReturn += ip.getPreco() * ip.getQtd();
        }
        toReturn = toReturn - p.getDesconto();
        return toReturn;
    }

    public Cliente getClientePedido() {
        return clientePedido;
    }

    public void setClientePedido(Cliente clientePedido) {
        this.clientePedido = clientePedido;
    }

    public String getTelFiltro() {
        return telFiltro;
    }

    public void setTelFiltro(String telFiltro) {
        this.telFiltro = telFiltro;
    }

    public String getNomeFiltro() {
        return nomeFiltro;
    }

    public void setNomeFiltro(String nomeFiltro) {
        this.nomeFiltro = nomeFiltro;
    }

    public StatusPedido getStatusFiltro() {
        return statusFiltro;
    }

    public void setStatusFiltro(StatusPedido statusFiltro) {
        this.statusFiltro = statusFiltro;
    }

    @FacesConverter(forClass = Pedido.class)
    public static class PedidoControllerConverter implements Converter {

        @Override
        public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
            if (value == null || value.length() == 0) {
                return null;
            }
            PedidoController controller = (PedidoController) facesContext.getApplication().getELResolver().
                    getValue(facesContext.getELContext(), null, "pedidoController");
            return controller.getPedido(getKey(value));
        }

        java.lang.Integer getKey(String value) {
            java.lang.Integer key;
            key = Integer.valueOf(value);
            return key;
        }

        String getStringKey(java.lang.Integer value) {
            StringBuilder sb = new StringBuilder();
            sb.append(value);
            return sb.toString();
        }

        @Override
        public String getAsString(FacesContext facesContext, UIComponent component, Object object) {
            if (object == null) {
                return null;
            }
            if (object instanceof Pedido) {
                Pedido o = (Pedido) object;
                return getStringKey(o.getId());
            } else {
                throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: " + Pedido.class.getName());
            }
        }
    }
}
